package com.yuju.common.core.convert;

import ma.glasnost.orika.Converter;
import ma.glasnost.orika.Mapper;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.ConfigurableMapper;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * Bean类型转换工具
 */
@Component
public class BeanMapper extends ConfigurableMapper implements ApplicationContextAware {


    private MapperFactory mapperFactory;
    private ApplicationContext applicationContext;


    public BeanMapper() {
        super(true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void configure(MapperFactory mapperFactory) {
        this.mapperFactory = mapperFactory;
        addAllSpringBeans(applicationContext);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void configureFactoryBuilder(final DefaultMapperFactory.Builder mapperFactoryBuilder) {
        mapperFactoryBuilder.mapNulls(false);
    }

    @SuppressWarnings("rawtypes")
    public void addMapper(Mapper<?, ?> mapper) {
        mapperFactory.classMap(mapper.getAType(), mapper.getBType())
                .byDefault()
                .customize((Mapper) mapper)
                .register();
    }

    /**
     * Registers a {@link Converter}
     *
     * @param converter
     */
    public void addConverter(Converter<?, ?> converter) {
        mapperFactory.getConverterFactory().registerConverter(converter);
    }

    @SuppressWarnings("rawtypes")
    private void addAllSpringBeans(final ApplicationContext applicationContext) {
        if(applicationContext == null) {
            return;
        }
        Map<String, Mapper> mappers = applicationContext.getBeansOfType(Mapper.class);
        for (Mapper mapper : mappers.values()) {
            addMapper(mapper);
        }
        Map<String, Converter> converters = applicationContext.getBeansOfType(Converter.class);
        for (Converter converter : converters.values()) {
            addConverter(converter);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
